﻿using System;
using System.Drawing;
using Microsoft.Win32;

namespace TimedScreenSaver
{
    internal enum ScreenPosition
    {
        Custom = 0,
        TopLeft = 1,
        TopCenter = 2,
        TopRight = 3,
        MidLeft = 4,
        MidCenter = 5,
        MidRight = 6,
        BottLeft = 7,
        BottCenter = 8,
        BottRight = 9
    }

    internal class Settings
    {
        #region Fields

        #region Register settings names

        private const string DefaultContentText = "Locked";
        private const ScreenPosition DefaultScreenPosition = ScreenPosition.MidCenter;
        private const int DefaultFontColor = -16744448;//"Green";
        private const int DefaultBackColor = -16777216;//"Black";
        private const string DefaultFont = "Microsoft Sans Serif, 36pt, style=Bold";
        private const string DatePatternWithYear = "dddd | d MMMM yyyy";
        private const string DatePatternWithoutYear = "dddd | d MMMM";
        private const string CustomScreenPoint = "50,50";

        private const string RegisterKeyPath = "SOFTWARE\\TimedScreenSaver";
        private const string ContentTextPattern = "ContentText";
        private const string CustomScrnPosition = "CustomScreenPosition";
        private const string LongTimeDisplayed = "IsLongTimeDisplayed";
        private const string TimeDisplayed = "IsTimeDisplayed";
        private const string DateDisplayed = "IsDateDisplayed";
        private const string YearDisplayed = "IsYearDisplayed";
        private const string ScrnPosition = "ScreenPosition";
        private const string FontPattern = "Font";
        private const string FontColorPattern = "FontColor";
        private const string BackColorPattern = "BackColor";

        #endregion 

        private readonly FontConverter _fontConverter = new FontConverter();
        private readonly PointConverter _pointConverter = new PointConverter();
        // how date font is smaller
        internal readonly byte DateFontSizeFactor = 4;

        #endregion

        #region Properties

        internal string ContentText { get; set; }
        internal string TimeText
        {
            get
            {
                return IsLongTimeDisplayed ? DateTime.Now.ToLongTimeString() : DateTime.Now.ToShortTimeString();
            }
        }
        internal string DateText
        {
            get
            {
                return DateTime.Today.ToString(IsYearDisplayed ? DatePatternWithYear : DatePatternWithoutYear);
            }
        }
        internal bool IsTimeDisplayed { get; set; }
        internal bool IsDateDisplayed { get; set; }
        internal bool IsLongTimeDisplayed { get; set; }
        internal bool IsYearDisplayed { get; set; }

        private ScreenPosition _positionOnScreen;
        internal ScreenPosition PositionOnScreen
        {
            get { return _positionOnScreen; }
            set
            {
                if(value != ScreenPosition.Custom)
                {
                    CustomScreenPosition = Point.Empty;
                }
                _positionOnScreen = value;
            }
        }

        internal Point CustomScreenPosition { get; set; }

        internal Font FontText { get; set; }
        internal Color FontColor { get; set; }
        internal Color BackColor { get; set; }

        #endregion

        #region Singleton

        private static volatile Settings _instance;
        private static readonly object SyncRootObject = new Object();

        private Settings()
        {
            SetDefaultValues();
        }

        public static Settings Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (SyncRootObject)
                    {
                        if (_instance == null)
                            _instance = new Settings();
                    }
                }

                return _instance;
            }
        }
        #endregion

        #region Methods

        /// <summary>
        /// Load display text from the Registry
        /// </summary>
        internal void LoadSettings()
        {
            try
            {
                RegistryKey key = Registry.CurrentUser.OpenSubKey(RegisterKeyPath);
                if (key == null)
                {
                    SetDefaultValues();
                }
                else
                {
                    ContentText = (string)key.GetValue(ContentTextPattern) ?? DefaultContentText;
                    IsTimeDisplayed = (Convert.ToBoolean(key.GetValue(TimeDisplayed)));
                    IsLongTimeDisplayed = (Convert.ToBoolean(key.GetValue(LongTimeDisplayed)));
                    IsDateDisplayed = (Convert.ToBoolean(key.GetValue(DateDisplayed)));
                    IsYearDisplayed = (Convert.ToBoolean(key.GetValue(YearDisplayed)));
                    PositionOnScreen = (ScreenPosition)(key.GetValue(ScrnPosition) ?? DefaultScreenPosition);
                    CustomScreenPosition = (Point)_pointConverter.ConvertFromString((string)key.GetValue(CustomScrnPosition) ?? CustomScreenPoint);
                    FontColor = Color.FromArgb((int)key.GetValue(FontColorPattern));
                    BackColor = Color.FromArgb((int)key.GetValue(BackColorPattern));
                    FontText = (Font)_fontConverter.ConvertFromString((string)key.GetValue(FontPattern) ?? DefaultFont);
                }
            }
            catch (Exception)
            {
                SetDefaultValues();
            }
        }

        /// <summary>
        /// Save text into the Registry.
        /// </summary>
        internal void SaveSettings()
        {
            try
            {
                // Create or get existing subkey
                RegistryKey key = Registry.CurrentUser.CreateSubKey(RegisterKeyPath);

                using (key)
                {
                    if (key != null)
                    {
                        key.SetValue(ContentTextPattern, ContentText, RegistryValueKind.String);
                        key.SetValue(TimeDisplayed, IsTimeDisplayed, RegistryValueKind.DWord);
                        key.SetValue(LongTimeDisplayed, IsLongTimeDisplayed, RegistryValueKind.DWord);
                        key.SetValue(DateDisplayed, IsDateDisplayed, RegistryValueKind.DWord);
                        key.SetValue(YearDisplayed, IsYearDisplayed, RegistryValueKind.DWord);
                        key.SetValue(ScrnPosition, PositionOnScreen, RegistryValueKind.DWord);
                        var customScreenPositionPoint = (PositionOnScreen == ScreenPosition.Custom) ? CustomScreenPosition : Point.Empty;
                        key.SetValue(CustomScrnPosition,_pointConverter.ConvertToString(customScreenPositionPoint), RegistryValueKind.String);
                        key.SetValue(FontColorPattern, FontColor.ToArgb(), RegistryValueKind.DWord);
                        key.SetValue(BackColorPattern, BackColor.ToArgb(), RegistryValueKind.DWord);
                        key.SetValue(FontPattern, _fontConverter.ConvertToString(FontText), RegistryValueKind.String);

                    }
                }
            }
            catch (Exception) {/*Couldn't write to registry*/}
        }

        private void SetDefaultValues()
        {
            ContentText = DefaultContentText;
            CustomScreenPosition = Point.Empty;
            IsLongTimeDisplayed = false;
            IsTimeDisplayed = true;
            IsDateDisplayed = true;
            IsYearDisplayed = false;
            PositionOnScreen = DefaultScreenPosition;
            FontText = (Font)_fontConverter.ConvertFromString(DefaultFont);
            FontColor = Color.FromArgb(DefaultFontColor);
            BackColor = Color.FromArgb(DefaultBackColor);
        }
        
        #endregion
    }
}
